package top.lixunda.ecommerce.server.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import top.lixunda.common.utils.ObjectValidators;
import top.lixunda.ecommerce.server.business.BaseServiceImpl;
import top.lixunda.ecommerce.server.business.api.entity.BusinessConstants;
import top.lixunda.ecommerce.server.business.api.entity.cache.CacheAdminUser;
import top.lixunda.ecommerce.server.business.api.entity.cache.CacheStore;
import top.lixunda.ecommerce.server.business.api.entity.cache.CacheStoreUser;
import top.lixunda.ecommerce.server.user.api.entity.db.AccountDO;
import top.lixunda.ecommerce.server.user.api.entity.db.RoleDO;
import top.lixunda.ecommerce.server.user.api.entity.db.StaffDO;
import top.lixunda.ecommerce.server.user.api.entity.db.UserRoleDO;
import top.lixunda.ecommerce.server.user.api.entity.dto.UserRoleInsertDTO;
import top.lixunda.ecommerce.server.user.api.entity.dto.UserRoleRemoveDTO;
import top.lixunda.ecommerce.server.user.mapper.AccountMapper;
import top.lixunda.ecommerce.server.user.mapper.RoleMapper;
import top.lixunda.ecommerce.server.user.mapper.UserRoleMapper;
import top.lixunda.ecommerce.server.user.service.IStaffService;
import top.lixunda.ecommerce.server.user.service.IUserRoleService;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 用户角色表，关联用户与角色表 服务类 服务类
 *
 * @author lixunda
 * @version time:2020/4/23 17:06
 */
@Service
public class UserRoleServiceImpl extends BaseServiceImpl<UserRoleMapper, UserRoleDO>
        implements IUserRoleService {

    private final AccountMapper accountMapper;

    private final RoleMapper roleMapper;

    private final IStaffService staffService;

    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
    @Autowired
    public UserRoleServiceImpl(AccountMapper accountMapper,
                               RoleMapper roleMapper,
                               IStaffService staffService) {
        this.accountMapper = accountMapper;
        this.roleMapper = roleMapper;
        this.staffService = staffService;
    }

    /**
     * 分配店铺角色
     *
     * @param list 角色操作DTO
     * @return 是否保存成功
     */
    @Override
    public Boolean allotStoreRole(List<UserRoleInsertDTO> list) {
        if (ObjectValidators.isEmpty(list)) {
            throw getAppException("分配角色失败！参数不能为空！");
        }
        LocalDateTime localDateTime = LocalDateTime.now();
        CacheStoreUser cacheStoreUser = currentStoreUserCacheNotNull();
        CacheStore cacheStore = currentStoreCacheNotNull();

        final List<UserRoleDO> insertList = new ArrayList<>(8);
        list.forEach(item -> {
            // 校验参数格式
            if (ObjectValidators.isEmpty(item) || ObjectValidators.isEmpty(item.getAccountList())
                    || ObjectValidators.isEmpty(item.getRoleIds())) {
                throw getAppException("分配角色失败！不合法的参数格式！账户编号列表和角色编号列表不能为空！");
            }
            // 校验用户
            List<Integer> accountIdList = item.getAccountList()
                    .stream()
                    .distinct()
                    .collect(Collectors.toList());
            List<AccountDO> accountList = accountMapper.selectBatchIds(accountIdList);
            accountList.forEach(item2 -> {
                if (!BusinessConstants.USER_TYPE_STORE.equals(item2.getUserType())) {
                    throw getAppException("分配角色失败！无法为用户 " + item2.getAccount() + " 添加角色，权限不足！");
                }
                if (BusinessConstants.USEABLE_FALSE.equals(item2.getForbidden())) {
                    throw getAppException("分配角色失败！无法为用户 " + item2.getAccount() + " 添加角色，角色已经禁用！");
                }
            });
            // 验证账户是否是本店铺的账户
            List<StaffDO> staffList = staffService.list(new LambdaQueryWrapper<StaffDO>()
                    .in(StaffDO::getUserId, accountIdList)
                    .eq(StaffDO::getUserType, BusinessConstants.USER_TYPE_STORE)
                    .eq(StaffDO::getSystemType, BusinessConstants.SYSTEM_TYPE_STORE)
                    .eq(StaffDO::getSystemId, cacheStore.getId()));
            if (ObjectValidators.isEmpty(staffList) || staffList.size() < accountIdList.size()) {
                throw getAppException("分配角色失败！部分账户不是本店账户，权限不足！");
            }
            // 校验角色
            List<Integer> roleIdList = item.getRoleIds();
            List<RoleDO> roleTempList = roleMapper.selectBatchIds(roleIdList);
            List<RoleDO> roleList = roleTempList.stream()
                    .filter(item2 -> {
                        if (item2.getManageType().equals(BusinessConstants.USER_TYPE_STORE)
                                && item2.getStoreId().equals(cacheStore.getId())) {
                            return false;
                        }
                        return !item2.getManageType().equals(BusinessConstants.USER_TYPE_ADMIN)
                                || !item2.getStoreEmploy().equals(BusinessConstants.FLAG_TRUE);
                    })
                    .collect(Collectors.toList());
            if (ObjectValidators.isNotEmpty(roleList)) {
                RoleDO roleDO = roleList.get(0);
                throw getAppException("分配角色失败！部分角色分配权限不足！ roleId："
                        + roleDO.getRoleId() + " roleName：" + roleDO.getRoleName());
            }
            // 添加用户角色
            list.forEach(item2 -> accountList.forEach(
                    temp1 -> roleList.forEach(
                            temp2 -> {
                                UserRoleDO userRoleDO = new UserRoleDO();
                                userRoleDO
                                        .setUserId(temp1.getAccount())
                                        .setUserName("")
                                        .setUserType(temp1.getUserType())
                                        .setRoleId(temp2.getRoleId())
                                        .setRoleName(temp2.getRoleName())
                                        .setBeginTime(item.getBeginTime())
                                        .setEndTime(item.getEndTime())
                                        .setCreateTime(localDateTime)
                                        .setCreateUserId(cacheStoreUser.getAccount())
                                        .setCreateUserName(cacheStoreUser.getName())
                                        .setCreateUserType(cacheStoreUser.getType());
                                insertList.add(userRoleDO);
                            })));
        });
        boolean success = this.saveBatch(insertList);
        if (!success) {
            throw getAppException("分配角色失败！插入数据失败！");
        }
        return true;
    }

    /**
     * 分配管理系统角色
     *
     * @param list 角色操作DTO
     * @return 是否保存成功
     */
    @Override
    public Boolean allotAdminRole(List<UserRoleInsertDTO> list) {
        if (ObjectValidators.isEmpty(list)) {
            throw getAppException("分配角色失败！参数不能为空！");
        }
        LocalDateTime localDateTime = LocalDateTime.now();
        CacheAdminUser cacheAdminUser = currentAdminUserCacheNotNull();

        final List<UserRoleDO> insertList = new ArrayList<>(8);
        list.forEach(item -> {
            // 校验参数格式
            if (ObjectValidators.isEmpty(item) || ObjectValidators.isEmpty(item.getAccountList())
                    || ObjectValidators.isEmpty(item.getRoleIds())) {
                throw getAppException("分配角色失败！不合法的参数格式！账户编号列表和角色编号列表不能为空！");
            }
            // 校验用户
            List<Integer> accountIdList = item.getAccountList();
            List<AccountDO> accountList = accountMapper.selectBatchIds(accountIdList);
            accountList.forEach(item2 -> {
                if (!BusinessConstants.USER_TYPE_ADMIN.equals(item2.getUserType())) {
                    throw getAppException("分配角色失败！无法为用户 " + item2.getAccount() + " 添加角色，权限不足！");
                }
            });
            // 校验角色
            List<Integer> roleIdList = item.getRoleIds();
            List<RoleDO> roleTempList = roleMapper.selectBatchIds(roleIdList);
            List<RoleDO> roleList = roleTempList.stream()
                    .filter(item2 -> !item2.getManageType().equals(BusinessConstants.USER_TYPE_ADMIN))
                    .collect(Collectors.toList());
            if (ObjectValidators.isNotEmpty(roleList)) {
                RoleDO roleDO = roleList.get(0);
                throw getAppException("分配角色失败！部分角色分配权限不足！ roleId："
                        + roleDO.getRoleId() + " roleName：" + roleDO.getRoleName());
            }
            // 添加用户角色
            list.forEach(item2 -> accountList.forEach(
                    temp1 -> roleList.forEach(
                            temp2 -> {
                                UserRoleDO userRoleDO = new UserRoleDO();
                                userRoleDO
                                        .setUserId(temp1.getAccount())
                                        .setUserName("")
                                        .setUserType(temp1.getUserType())
                                        .setRoleId(temp2.getRoleId())
                                        .setRoleName(temp2.getRoleName())
                                        .setBeginTime(item.getBeginTime())
                                        .setEndTime(item.getEndTime())
                                        .setCreateTime(localDateTime)
                                        .setCreateUserId(cacheAdminUser.getAccount())
                                        .setCreateUserName(cacheAdminUser.getName())
                                        .setCreateUserType(cacheAdminUser.getType());
                                insertList.add(userRoleDO);
                            })));
        });
        boolean success = this.saveBatch(insertList);
        if (!success) {
            throw getAppException("分配角色失败！插入数据失败！");
        }
        return true;
    }

    /**
     * 移除店铺角色
     *
     * @param list 角色操作DTO
     * @return 是否移除成功
     */
    @Override
    public Boolean removeStoreRoleAllot(List<UserRoleRemoveDTO> list) {
        if (ObjectValidators.isEmpty(list)) {
            throw getAppException("移除分配角色失败！参数不能为空！");
        }
        CacheStoreUser cacheStoreUser = currentStoreUserCacheNotNull();
        CacheStore cacheStore = currentStoreCacheNotNull();
        List<Integer> userRoleIdList = new ArrayList<>();
        // 校验是否可以移除，是否是本店铺账户
        List<Integer> accountIdList = list.stream()
                .map(UserRoleRemoveDTO::getAccount)
                .collect(Collectors.toList());
        List<StaffDO> staffList = staffService.list(new LambdaQueryWrapper<StaffDO>()
                .in(StaffDO::getUserId, accountIdList));
        staffList.forEach(item -> {
            if (!BusinessConstants.SYSTEM_TYPE_STORE.equals(item.getSystemType())
                    || !cacheStore.getId().equals(item.getSystemId())
                    || !BusinessConstants.USER_TYPE_STORE.equals(item.getUserType())) {
                throw getAppException("移除分配角色失败！用户角色信息不存在！");
            }
        });
        // 校验用户角色是否存在
        list.forEach(item -> {
            UserRoleDO userRoleDO = this.getOne(new LambdaQueryWrapper<UserRoleDO>()
                    .eq(UserRoleDO::getUserId, item.getAccount())
                    .eq(UserRoleDO::getUserType, BusinessConstants.USER_TYPE_STORE)
                    .eq(UserRoleDO::getRoleId, item.getRoleId()), false);
            if (ObjectValidators.isEmpty(userRoleDO)) {
                throw getAppException("移除分配角色失败！用户角色信息不存在！");
            }
            // 校验通过，添加移除角色
            userRoleIdList.add(userRoleDO.getId());
        });

        boolean success = this.update(new LambdaUpdateWrapper<UserRoleDO>()
                .in(UserRoleDO::getId, userRoleIdList)
                .set(UserRoleDO::getRemoveTime, LocalDateTime.now())
                .set(UserRoleDO::getRemoveUserId, cacheStoreUser.getAccount())
                .set(UserRoleDO::getRemoveUserName, cacheStoreUser.getName())
                .set(UserRoleDO::getRemoveUserType, cacheStoreUser.getType()));
        if (!success) {
            throw getAppException("移除分配角色失败！修改数据失败！");
        }

        success = this.removeByIds(userRoleIdList);
        if (!success) {
            throw getAppException("移除分配角色失败！删除数据失败！");
        }
        return true;
    }

    /**
     * 移除管理系统角色
     *
     * @param list 角色操作DTO
     * @return 是否移除成功
     */
    @Override
    public Boolean removeAdminRoleAllot(List<UserRoleRemoveDTO> list) {
        if (ObjectValidators.isEmpty(list)) {
            throw getAppException("移除分配角色失败！参数不能为空！");
        }
        CacheAdminUser cacheAdminUser = currentAdminUserCacheNotNull();
        List<Integer> userRoleIdList = new ArrayList<>();
        list.forEach(item -> {
            // 校验用户角色是否存在
            UserRoleDO userRoleDO = this.getOne(new LambdaQueryWrapper<UserRoleDO>()
                    .eq(UserRoleDO::getUserId, item.getAccount())
                    .eq(UserRoleDO::getUserType, BusinessConstants.USER_TYPE_ADMIN)
                    .eq(UserRoleDO::getRoleId, item.getRoleId()), false);
            if (ObjectValidators.isEmpty(userRoleDO)) {
                throw getAppException("移除分配角色失败！用户角色信息不存在！");
            }
            userRoleIdList.add(userRoleDO.getId());
        });

        boolean success = this.update(new LambdaUpdateWrapper<UserRoleDO>()
                .in(UserRoleDO::getId, userRoleIdList)
                .set(UserRoleDO::getRemoveTime, LocalDateTime.now())
                .set(UserRoleDO::getRemoveUserId, cacheAdminUser.getAccount())
                .set(UserRoleDO::getRemoveUserName, cacheAdminUser.getName())
                .set(UserRoleDO::getRemoveUserType, cacheAdminUser.getType()));
        if (!success) {
            throw getAppException("移除分配角色失败！修改数据失败！");
        }

        success = this.removeByIds(userRoleIdList);
        if (!success) {
            throw getAppException("移除分配角色失败！删除数据失败！");
        }
        return true;
    }

    /**
     * 根据分配编号移除店铺角色分配
     *
     * @param list 分配编号列表
     * @return 是否移除成功
     */
    @Override
    public Boolean removeStoreRoleAllotByIds(List<Integer> list) {
        if (ObjectValidators.isEmpty(list)) {
            throw getAppException("移除分配角色失败！参数不能为空！");
        }
        CacheStoreUser cacheStoreUser = currentStoreUserCacheNotNull();
        CacheStore cacheStore = currentStoreCacheNotNull();
        List<UserRoleDO> userRoleList = (List<UserRoleDO>) this.listByIds(list);
        if (ObjectValidators.isEmpty(userRoleList) || userRoleList.size() < list.size()) {
            throw getAppException("移除分配角色失败！部分用户角色信息不存在！");
        }
        // 校验
        List<Integer> accountIdList = userRoleList.stream()
                .map(UserRoleDO::getUserId)
                .distinct()
                .collect(Collectors.toList());
        List<AccountDO> accountList = accountMapper.selectBatchIds(accountIdList);
        accountList = accountList.stream()
                .filter(item -> !item.getUserType().equals(BusinessConstants.USER_TYPE_STORE))
                .collect(Collectors.toList());
        // 验证账户是否是本店铺的账户
        List<StaffDO> staffList = staffService.list(new LambdaQueryWrapper<StaffDO>()
                .in(StaffDO::getUserId, accountIdList)
                .eq(StaffDO::getUserType, BusinessConstants.USER_TYPE_STORE)
                .eq(StaffDO::getSystemType, BusinessConstants.SYSTEM_TYPE_STORE)
                .eq(StaffDO::getSystemId, cacheStore.getId()));
        if (ObjectValidators.isEmpty(staffList) || staffList.size() < accountIdList.size()) {
            throw getAppException("分配角色失败！部分账户不是本店账户，权限不足！");
        }

        if (ObjectValidators.isNotEmpty(accountList)) {
            throw getAppException("移除分配角色失败！部分用户角色权限不足！ account：" + accountList.get(0).getAccount());
        }
        // 移除
        boolean success = this.update(new LambdaUpdateWrapper<UserRoleDO>()
                .in(UserRoleDO::getId, list)
                .set(UserRoleDO::getRemoveTime, LocalDateTime.now())
                .set(UserRoleDO::getRemoveUserId, cacheStoreUser.getAccount())
                .set(UserRoleDO::getRemoveUserName, cacheStoreUser.getName())
                .set(UserRoleDO::getRemoveUserType, cacheStoreUser.getType()));
        if (!success) {
            throw getAppException("移除分配角色失败！修改数据失败！");
        }

        success = this.removeByIds(list);
        if (!success) {
            throw getAppException("移除分配角色失败！删除数据失败！");
        }
        return true;
    }

    /**
     * 根据分配编号移除管理系统角色分配
     *
     * @param list 分配编号列表
     * @return 是否移除成功
     */
    @Override
    public Boolean removeAdminRoleAllotByIds(List<Integer> list) {
        if (ObjectValidators.isEmpty(list)) {
            throw getAppException("移除分配角色失败！参数不能为空！");
        }
        CacheAdminUser cacheAdminUser = currentAdminUserCacheNotNull();
        List<UserRoleDO> userRoleList = (List<UserRoleDO>) this.listByIds(list);
        if (ObjectValidators.isEmpty(userRoleList)) {
            throw getAppException("移除分配角色失败！用户角色信息不存在！");
        }
        // 校验
        List<Integer> accountIdList = userRoleList.stream()
                .map(UserRoleDO::getUserId)
                .collect(Collectors.toList());
        List<AccountDO> accountList = accountMapper.selectBatchIds(accountIdList);
        accountList = accountList.stream()
                .filter(item -> !item.getUserType().equals(BusinessConstants.USER_TYPE_ADMIN))
                .collect(Collectors.toList());
        if (ObjectValidators.isNotEmpty(accountList)) {
            throw getAppException("移除分配角色失败！部分用户角色权限不足！ account：" + accountList.get(0).getAccount());
        }
        // 移除
        boolean success = this.update(new LambdaUpdateWrapper<UserRoleDO>()
                .in(UserRoleDO::getId, list)
                .set(UserRoleDO::getRemoveTime, LocalDateTime.now())
                .set(UserRoleDO::getRemoveUserId, cacheAdminUser.getAccount())
                .set(UserRoleDO::getRemoveUserName, cacheAdminUser.getName())
                .set(UserRoleDO::getRemoveUserType, cacheAdminUser.getType()));
        if (!success) {
            throw getAppException("移除分配角色失败！修改数据失败！");
        }

        success = this.removeByIds(list);
        if (!success) {
            throw getAppException("移除分配角色失败！删除数据失败！");
        }
        return true;
    }
}
